package day18.Junit_reflect_annotation_proxy.proxydemo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxtUtil
{
//    public static Star_Aciton CreateProxy(Star s)//创建代理，还要把代理要做的事情给声明好，代理原本就是Object类型，要强转成接口，那样就可以直接返回给一个接口类型了。在上层调用形式就类似，把实现类对象给包装成强转之后的代理类对象返回给接口类
//    {                          //代理类型是Object类型，强转成行为接口类.然后可以代替是实现类做东西，invoke代表了他的接口的具体实现类（star）的方法（行为），
//        Star_Aciton proxy=(Star_Aciton)Proxy.newProxyInstance(ProxtUtil.class.getClassLoader(), s.getClass().getInterfaces(), new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//            {
//                if("sing".equals(method.getName()))
//                {
//                    System.out.println("代理来干一些杂活（比如收唱歌钱）");
//                    System.out.println("开始叫真正的明星来干核心工作");
//                    method.invoke(s,args);//我觉得你真正要调的是明星的比如唱歌方法，那对象是s（Star类型）,那如果调的是形参中的proxy，相当于调代理的唱歌方法。。。。。
//                    return null;
//                }
//                else
//                {  System.out.println("代理来干一些杂活（比如收唱歌钱）");
//                    System.out.println("开始叫真正的明星来干核心工作");
//                    String result=(String)method.invoke(s,args);
//                    return result;
//                }
//
//
//            }
//        });
//        return proxy;
//    }

    //尝试把创建代理的方法给优化，让他解耦合能力更强，更广泛
    public static <T> T CreateProxy(T s)//这里是泛型接的是实现类对象返回的是接口类型。也就是说我传任意一个接口和实现类都可以为当前实现类创建一个代理对象，那这个代理对象除了拥有实现类的核心代码还可以做其他的事情，比如计时，用来测性能
                         // 创建代理，还要把代理要做的事情给声明好，代理原本就是Object类型，要强转成接口，那样就可以直接返回给一个接口类型了。在上层调用形式就类似，把实现类对象给包装成强转之后的代理类对象返回给接口类
    {                          //代理类型是Object类型，强转成行为接口类.然后可以代替是实现类做东西，invoke代表了他的接口的具体实现类（star）的方法（行为），
        T proxy=(T)Proxy.newProxyInstance(ProxtUtil.class.getClassLoader(), s.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
            {
                if("sing".equals(method.getName()))
                {
                    System.out.println("代理来干一些杂活（比如收唱歌钱）");
                    System.out.println("开始叫真正的明星来干核心工作");
                    method.invoke(s,args);//我觉得你真正要调的是明星的比如唱歌方法，那对象是s（Star类型）,那如果调的是形参中的proxy，相当于调代理的唱歌方法那就跟上层的sa.sing("asd")一样了都是调匿名类里面的invoke方法就一直跟个递归一样
                    return null;
                }
                else
                {  System.out.println("代理来干一些杂活（比如收唱歌钱）");
                    System.out.println("开始叫真正的明星来干核心工作");
                    String result=(String)method.invoke(s,args);
                    return result;
                }


            }
        });
        return proxy;
    }
}
